//************************************************************************
// author	:	vera												
// date		:	2011/4/7 23:13 					                 
//************************************************************************
#ifndef SL_QUAT_H_
#define SL_QUAT_H_
#include "Config.h"
#include "Vector3.h"
namespace sl
{
	class SL_EXPORT Quat
	{
	public:
		typedef float value_type;

		value_type _v[4];

		inline Quat()
		{
			_v[0] = 0.0f;
			_v[1] = 0.0f;
			_v[2] = 0.0f;
			_v[3] = 1.0f;
			
		}

		inline Quat( value_type x,value_type y, value_type z, value_type w )
		{
			_v[0] = x;
			_v[1] = y;
			_v[2] = z;
			_v[3] = w;
		}

		inline Quat( const value_type rAngle, const Vector3& rAxis )
		{
			fromAngleAxis( rAngle, rAxis );
		}

		~Quat()
		{

		}

		inline Quat& operator = (const Quat& v) { _v[0]=v._v[0];  _v[1]=v._v[1]; _v[2]=v._v[2]; _v[3]=v._v[3]; return *this; }

		inline bool operator == (const Quat& v) const { return _v[0]==v._v[0] && _v[1]==v._v[1] && _v[2]==v._v[2] && _v[3]==v._v[3]; }

		inline bool operator != (const Quat& v) const { return _v[0]!=v._v[0] || _v[1]!=v._v[1] || _v[2]!=v._v[2] || _v[3]!=v._v[3]; }

		inline bool operator <  (const Quat& v) const
		{
			if (_v[0]<v._v[0]) return true;
			else if (_v[0]>v._v[0]) return false;
			else if (_v[1]<v._v[1]) return true;
			else if (_v[1]>v._v[1]) return false;
			else if (_v[2]<v._v[2]) return true;
			else if (_v[2]>v._v[2]) return false;
			else return (_v[3]<v._v[3]);
		}

		inline value_type & x() { return _v[0]; }
		inline value_type & y() { return _v[1]; }
		inline value_type & z() { return _v[2]; }
		inline value_type & w() { return _v[3]; }

		inline value_type x() const { return _v[0]; }
		inline value_type y() const { return _v[1]; }
		inline value_type z() const { return _v[2]; }
		inline value_type w() const { return _v[3]; }

		inline void fromAngleAxis( const value_type rAngle, const Vector3 rAxis )
		{
			//   q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
			value_type HalfAngle =  0.5*rAngle;
			value_type Sin = sinf(HalfAngle);
			_v[0] = Sin*rAxis.x();
			_v[1] = Sin*rAxis.y();
			_v[2] = Sin*rAxis.z();
			_v[3] = cosf(HalfAngle);

		}

		inline void toAngleAxis( value_type rAngle, Vector3 & rAxis ) const
		{
			value_type fSqrLength = _v[0]*_v[0]+_v[1]*_v[1]+_v[2]*_v[2];
			if ( fSqrLength > 0.0 )
			{
				rAngle = 2.0*acosf(_v[3]);
				value_type fInvLength = sqrtf(fSqrLength);
				rAxis._v[0] = _v[0]*fInvLength;
				rAxis._v[1] = _v[1]*fInvLength;
				rAxis._v[2] = _v[2]*fInvLength;
			}
			else
			{
				// angle is 0 (mod 2*pi), so any axis will do
				rAngle	 = 0.0f;
				rAxis._v[0] = 1.0f;
				rAxis._v[1] = 0.0f;
				rAxis._v[2] = 0.0f;
			}
		}


	};

}

#endif

